/*
 * Copyright (c) 2024 endless-sky
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include "media_stream.h"
#include <mutex>
#include <set>
#include <gst/gst.h>
#include <gst/app/gstappsink.h>
#include <gst/rtsp-server/rtsp-server.h>
#include <gst/rtsp-server/rtsp-media.h>
#include <memory>
#include <map>
#include <string>
#include <thread>
#include <atomic>
#include "nlohmann/json.hpp"
#include "stream_flow_control.h"

namespace El {
namespace StreamService {

/**
 * @brief RTSP流媒体服务器类
 * 提供基于GStreamer的RTSP实时流媒体和录制服务
 */
class StreamGstRtsp {
    DISALLOW_COPY_AND_MOVE(StreamGstRtsp);

public:
    /**
     * @brief 媒体数据结构
     * 包含单个媒体流的所有相关数据和元素
     */
    struct MediaData {
        StreamGstRtsp *server;                  ///< 指向服务器实例的指针
        int32_t channel;                        ///< 通道编号
        int32_t streamType;                     ///< 流类型
        Media::StreamSourcePtr streamSource;    ///< 流媒体源指针
        int32_t streamHandle;                   ///< 流句柄
        GstElement *appsrcVideo;                ///< 视频应用源元素
        GstElement *appsrcAudio;                ///< 音频应用源元素
        std::shared_ptr<StreamFlowControl> flowControl; ///< 流控管理器

        /**
         * @brief 清理媒体数据资源
         */
        void Cleanup()
        {
            if (streamSource) {
                streamSource->Stop();
            }
            if (appsrcVideo) {
                gst_object_unref(appsrcVideo);
                appsrcVideo = nullptr;
            }
            if (appsrcAudio) {
                gst_object_unref(appsrcAudio);
                appsrcAudio = nullptr;
            }
            flowControl.reset();
        }
    };

    using MediaDataPtr = std::shared_ptr<MediaData>;

    /**
     * @brief 获取单例实例
     * @return StreamGstRtsp& 单例实例引用
     */
    static StreamGstRtsp &GetInstance();

    /**
     * @brief 构造函数
     */
    StreamGstRtsp();

    /**
     * @brief 析构函数
     */
    ~StreamGstRtsp();

    /**
     * @brief 启动RTSP服务
     * @return bool 成功返回true，失败返回false
     */
    bool Start();

    /**
     * @brief 停止RTSP服务
     */
    void Stop();

    /**
     * @brief 处理新媒体创建事件
     * @param factory 媒体工厂指针
     * @param media 媒体对象指针
     */
    void HandleNewMedia(GstRTSPMediaFactory *factory, GstRTSPMedia *media);

    /**
     * @brief 处理客户端连接事件
     * @param server RTSP服务器指针
     * @param client RTSP客户端指针
     */
    void HandleClientConnected(GstRTSPServer *server, GstRTSPClient *client);

    /**
     * @brief 处理客户端断开连接事件
     * @param client RTSP客户端指针
     */
    void HandleClientDisconnected(GstRTSPClient *client);

    /**
     * @brief 处理录制媒体配置
     * @param media 媒体对象指针
     * @param channel 通道号
     */
    void HandleRecordMediaConfigure(GstRTSPMedia *media, int channel);

    /**
     * @brief 处理客户端Opus音频采样数据
     * @param appsink 应用sink指针
     * @param userData 用户数据
     * @return GstFlowReturn 流状态返回值
     */
    GstFlowReturn HandleOpusAudioSample(GstAppSink *appsink, gpointer userData);

    /**
     * @brief 处理录制媒体取消准备事件
     * @param media 媒体对象指针
     */
    void HandleRecordMediaUnprepared(GstRTSPMedia *media);

private:
    /**
     * @brief 推送音视频帧到GStreamer
     * @param frame 媒体帧指针
     * @param stream 流数据对象
     */
    void PushFrame(const Media::MediaFramePtr &frame, MediaDataPtr stream);

    /**
     * @brief 清理指定的媒体资源
     * @param handle 媒体句柄
     */
    void CleanupMedia(int handle);

    /**
     * @brief 获取AAC采样率索引
     * @param sampleRate 采样率
     * @return uint8_t 采样率索引
     */
    uint8_t GetAacSampleRateIndex(int sampleRate);

    bool OnRtspConfigChanged(const nlohmann::json &config);
    bool ApplyRtspConfigLocked(const nlohmann::json &config);
    bool StartServerLocked();
    void StopServerLocked();

private:
    GMainLoop *loop_;                             ///< GLib主循环
    GstRTSPServer *server_;                       ///< RTSP服务器实例
    std::thread mainLoopThread_;                  ///< 主循环线程
    std::map<int, MediaDataPtr> mediaData_;       ///< 媒体数据映射表
    std::mutex mediaDataMutex_;                   ///< 媒体数据互斥锁
    bool audioEnable_{false};                     ///< 音频启用标志
    std::string audioCodec_;                      ///< 音频编解码器类型
    int audioSampleRate_{8000};                   ///< 音频采样率
    bool recordAudioStreamActive_ = false;        ///< 录制音频流活跃状态
    std::mutex recordStateMutex_;                 ///< 录制状态互斥锁
    GstRTSPClient *activeRecordClient_ = nullptr; ///< 当前活跃的录制客户端，只允许一个
    std::mutex lifecycleMutex_;
    bool initialized_{false};
    bool rtspEnabled_{true};
    std::string servicePort_{"554"};
    int32_t configListenerId_{-1};
};

} // namespace StreamService
} // namespace El
